/**
Company: Sarkar software technologys
WebSite: http://www.sarkar.cn
Author: yeganaaa
Date : 8/1/18
Time: 4:14 AM
 */

package com.ug_project.dict.engine.wordtable

import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.channels.SeekableByteChannel

class WordRow(val wordTable: WordTable, var startPosition: Int = 0) : Iterable<Int> {
    companion object {
        const val headerSize = 4
        const val pointerSize = 4
    }

    private var _unicode: Short = 0
    private var _layerCount: Short = 0
    var unicode: Int
        get() = (_unicode + Short.MAX_VALUE)
        set(value) {
            _unicode = (value - Short.MAX_VALUE).toShort()
        }
    var layerCount: Int
        get() = (_layerCount + Short.MAX_VALUE)
        set(value) {
            _layerCount = (value - Short.MAX_VALUE).toShort()
        }
    val size: Int
        get() = headerSize + (layerCount * pointerSize)

    private val headerBuffer by lazy { ByteBuffer.allocate(headerSize).apply { order(ByteOrder.BIG_ENDIAN) } }
    private val channel = wordTable.channel
    var pointers = intArrayOf()

    private fun SeekableByteChannel.resetToRowHome() {
        this.position(startPosition.toLong())
    }

    private fun SeekableByteChannel.resetToRowPointerHome() {
        channel.position((startPosition + headerSize).toLong())
    }

    private fun readHeader() {
        channel.resetToRowHome()
        headerBuffer.clear()
        val readed = channel.read(headerBuffer)
        if (readed < 1) {
            layerCount = 0
            unicode = 0
            return
        }
        headerBuffer.flip()
        _unicode = headerBuffer.short
        _layerCount = headerBuffer.short
    }

    private fun writeHeader() {
        if (unicode == 0) throw Exception("Zero unicode value")
        channel.resetToRowHome()
        headerBuffer.clear()
        headerBuffer.putShort(_unicode)
        headerBuffer.putShort(_layerCount)
        headerBuffer.flip()
        channel.write(headerBuffer)
    }

    private fun readPointer() {
        channel.resetToRowPointerHome()
        val pointerBuffer = ByteBuffer.allocate(layerCount * pointerSize)
        val readed = channel.read(pointerBuffer)
        if (readed < 1) return
        pointerBuffer.flip()
        pointers = IntArray(layerCount)
        for (index in 0 until layerCount) {
            pointers[index] = pointerBuffer.int
        }
    }

    private fun writePointer() {
        channel.resetToRowPointerHome()
        val pointerBuffer = ByteBuffer.allocate(layerCount * pointerSize)
        pointers.forEach { pointerBuffer.putInt(it) }
        pointerBuffer.flip()
        channel.write(pointerBuffer)
    }

    private fun read() {
        readHeader()
        readPointer()
    }

    fun write() {
        writeHeader()
        writePointer()
    }

    fun add(pointer: Int, layer: Int) {
        if (layer < layerCount) throw Exception("layer $layer already exists.")
        val temp = IntArray((layer + 1) - layerCount)
        pointers = intArrayOf(*pointers, *temp)
        pointers[layer] = pointer
        layerCount += temp.size
//        write()
    }

    fun remove(pointer: Int){
        pointers = intArrayOf(*pointers.filter { it != pointer }.toIntArray())
        layerCount--
//        write()
    }

    override fun iterator(): Iterator<Int> = WordRowIterator(this)

    init {
        read()
    }
}
